package com.chongchong.flow.offline.controller;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.CharUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.chongchong.common.tool.CommonUtil;
import com.chongchong.flow.constant.FlowApprovalType;
import com.chongchong.flow.constant.FlowConstant;
import com.chongchong.flow.constant.FlowTaskStatus;
import com.chongchong.flow.constant.StatusEnum;
import com.chongchong.flow.entity.FlowEntry;
import com.chongchong.flow.entity.FlowEntryPublish;
import com.chongchong.flow.entity.FlowTaskComment;
import com.chongchong.flow.entity.FlowWorkOrder;
import com.chongchong.flow.exception.FlowOperationException;
import com.chongchong.flow.offline.service.IFlowOfflineOperationService;
import com.chongchong.flow.offline.wrapper.FlowWorkOrderWrapper;
import com.chongchong.flow.service.IFlowApiService;
import com.chongchong.flow.service.IFlowEntryService;
import com.chongchong.flow.wrapper.FlowEntityWrapper;
import com.chongchong.online.entity.*;
import com.chongchong.online.service.*;
import com.chongchong.core.mp.annotation.DisableDataFilter;
import com.chongchong.core.mp.object.MyModelUtil;
import com.chongchong.core.mp.support.Condition;
import com.chongchong.core.mp.support.Query;
import com.chongchong.core.secure.SysUser;
import com.chongchong.core.secure.utils.SecureUtil;
import com.chongchong.core.tool.api.R;
import com.chongchong.core.tool.utils.BeanUtil;
import com.chongchong.core.tool.utils.DateUtil;
import com.chongchong.core.tool.utils.Func;
import com.chongchong.flow.constant.FlowApprovalType;
import com.chongchong.flow.constant.FlowConstant;
import com.chongchong.flow.constant.FlowTaskStatus;
import com.chongchong.flow.constant.StatusEnum;
import com.chongchong.flow.dto.FlowTaskCommentDto;
import com.chongchong.flow.dto.TaskAssigneeDto;
import com.chongchong.flow.dto.UserAssigneeDto;
import com.chongchong.flow.exception.FlowOperationException;
import com.chongchong.flow.offline.service.IFlowOfflineOperationService;
import com.chongchong.flow.offline.wrapper.FlowWorkOrderWrapper;
import com.chongchong.flow.service.IFlowApiService;
import com.chongchong.flow.service.IFlowEntryService;
import com.chongchong.flow.service.IFlowTaskCommentService;
import com.chongchong.flow.service.IFlowWorkOrderService;
import com.chongchong.flow.util.FlowOperationHelper;
import com.chongchong.flow.vo.FlowEntryVo;
import com.chongchong.flow.vo.FlowTaskVo;
import com.chongchong.flow.vo.FlowWorkOrderVo;
import com.chongchong.flow.vo.TaskInfoVo;
import com.chongchong.flow.wrapper.FlowEntityWrapper;
import com.chongchong.online.dto.OnlineFilterDto;
import com.chongchong.online.entity.constant.FieldFilterType;
import com.chongchong.online.entity.constant.RelationType;
import com.chongchong.online.object.ColumnData;
import com.chongchong.online.util.OnlineOperationHelper;
import com.chongchong.online.util.OnlineUtil;
import com.github.xiaoymin.knife4j.annotations.ApiSupport;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.activiti.engine.HistoryService;
import org.activiti.engine.TaskService;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.history.HistoricTaskInstanceQuery;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.activiti.engine.task.TaskInfo;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.xml.stream.XMLStreamException;
import java.text.ParseException;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 流程操作接口类
 *
 * @author Jerry
 * @date 2021-06-06
 */
@Api(tags = "线下表单标案流程操作接口")
@Slf4j
@RestController
//@AllArgsConstructor
@RequestMapping("/flowOfflineOperation")
@ApiSupport(order = 2)
public class FlowOfflineOperationController {
	@Autowired
	private IFlowEntryService flowEntryService;
	@Autowired
	private IFlowApiService flowApiService;
	@Autowired
	private FlowOperationHelper flowOperationHelper;
	@Autowired
	private IFlowOfflineOperationService flowOfflineOperationService;
	@Autowired
	private IFlowWorkOrderService flowWorkOrderService;
	@Autowired
	private IOnlineFormService onlineFormService;
	@Autowired
	private OnlineOperationHelper onlineOperationHelper;
	@Autowired
	private IOnlineOperationService onlineOperationService;
	@Autowired
	private IOnlineTableService onlineTableService;
	@Autowired
	private IFlowTaskCommentService flowTaskCommentService;
	@Autowired
	private IOnlineColumnService onlineColumnService;
	@Autowired
	private IOnlineDatasourceRelationService onlineDatasourceRelationService;
	private List<UserAssigneeDto> userNameByAccounts;

	@Autowired
	TaskService taskService;
	@Autowired
	HistoryService historyService;


	/**
	 * 根据指定流程的主版本，发起一个流程实例，同时作为第一个任务节点的执行人，执行第一个用户任务。
	 * 该接口无需数据权限过滤，因此用DisableDataFilter注解标注。如果当前系统没有支持数据权限过滤，该注解不会有任何影响。
	 *
	 * @param processDefinitionKey 流程定义标识。
	 *                             //	 * @param flowTaskCommentDtoJson   审批意见。
	 *                             //	 * @param taskVariableData     流程任务变量数据。
	 *                             //	 * @param masterData           流程审批相关的主表数据。
	 *                             //	 * @param slaveData            流程审批相关的多个从表数据。
	 * @return 应答结果对象。
	 */

	@DisableDataFilter
	@PostMapping("/startAndTakeUserTask/{processDefinitionKey}")
	@ApiOperation(notes = "启动流程", value = "启动流程")
	public R<Void> startAndTakeUserTask(
		@PathVariable("processDefinitionKey") String processDefinitionKey,
//		@RequestBody(required = true) FlowTaskCommentDto flowTaskCommentDto,
//		@RequestBody JSONObject taskVariableData,
//		@RequestBody(required = true) JSONObject masterData,
//		@RequestBody JSONObject slaveData) {
		@RequestBody Map<String, Object> startMap,
		SysUser user) throws XMLStreamException {

		String errorMessage;

		FlowTaskCommentDto flowTaskCommentDto = JSONObject.parseObject((String) startMap.get("flowTaskCommentDto"), FlowTaskCommentDto.class);
		JSONObject masterData = JSONObject.parseObject((String) startMap.get("masterData"));
		JSONObject taskVariableData = JSONObject.parseObject((String) startMap.get("taskVariableData"));
		JSONObject slaveData = JSONObject.parseObject((String) startMap.get("slaveData"));

		//主数据id
		Long masterDataId = masterData.getLong("id");


		// 1. 验证流程数据的合法性。
		R<FlowEntry> flowEntryResult = flowOperationHelper.verifyAndGetFlowEntry(processDefinitionKey);
		if (!flowEntryResult.isSuccess()) {
			return R.fail(flowEntryResult.getMsg());
		}
		// 2. 验证流程一个用户任务的合法性。
		FlowEntryPublish flowEntryPublish = flowEntryResult.getData().getMainFlowEntryPublish();
		if (!flowEntryPublish.getActiveStatus()) {
			errorMessage = "数据验证失败，当前流程发布对象已被挂起，不能启动新流程！";
			return R.fail(errorMessage);
		}
		R<TaskInfoVo> taskInfoResult =
			flowOperationHelper.verifyAndGetInitialTaskInfoXml(flowEntryResult.getData().getBpmnXml(),flowEntryPublish, true);
		if (!taskInfoResult.isSuccess()) {
			return R.fail(taskInfoResult.getMsg());
		}
		TaskInfoVo taskInfo = taskInfoResult.getData();

		// 3. 通过流程定义信息获取表单信息, 获取表单关联主表信息。
		String formName = taskInfo.getRouterName();
		QueryWrapper<OnlineForm> onlineFormQueryWrapper = new QueryWrapper<>();
		onlineFormQueryWrapper.eq("form_name", formName);
		OnlineForm onlineForm = onlineFormService.getOne(onlineFormQueryWrapper);

		R<OnlineDatasource> datasourceResult = this.verifyAndGetOnlineDatasource(onlineForm.getFormId());
		if (!datasourceResult.isSuccess()) {
			return R.fail(datasourceResult.getMsg());
		}
		OnlineDatasource datasource = datasourceResult.getData();

		OnlineTable masterTable = datasource.getMasterTable();

		FlowTaskComment flowTaskComment = BeanUtil.copyProperties(flowTaskCommentDto, FlowTaskComment.class);
		slaveData = salveDataBasic(slaveData, user, StatusEnum.SUBMIT.getValue());
		masterData = masterDataBasic(masterData,user,StatusEnum.SUBMIT.getValue(),onlineForm.getFormCode(),StatusEnum.getEnum(1).getDesc()+"_"+flowTaskComment.getApprovalType());

		//若为新设备小件立项
		if ("en_new_device_info".equals(masterTable.getTableName())){
			String project_no = masterData.getString("project_no");
			//验证远程测试是否完成
			R<String> remoteTestMsg = onlineOperationHelper.validateRemoteTest(datasource.getDatasourceId(),String.valueOf(masterDataId),slaveData,null,project_no);
			if (!remoteTestMsg.isSuccess()) {
				return R.fail(remoteTestMsg.getMsg());
			}
		}else if ("en_new_supplier_copy_package".equals(masterTable.getTableName())){ //若为新供应商复制
			String project_no = masterData.getString("project_no");
			String copy_supplier_no = masterData.getString("copy_supplier_no");
			//验证是否发起重复供应商
			R<String> supplierCopyMsg = onlineOperationHelper.validateSupplierCopy(masterTable,project_no,copy_supplier_no);
			if (!supplierCopyMsg.isSuccess()) {
				return R.fail(supplierCopyMsg.getMsg());
			}
		}

		// 4. 为本次流程操作构建数据。
		R<List<ColumnData>> columnDataListResult =
			onlineOperationHelper.buildTableData(masterTable, masterData, masterDataId==null?false:true, null);
		if (!columnDataListResult.isSuccess()) {
			return R.fail(((R) columnDataListResult).getMsg());
		}

		// 5. 保存在线表单提交的数据，同时启动流程和自动完成第一个用户任务。
		if (slaveData == null) {
			if (masterDataId == null) { //新增提交
				flowOfflineOperationService.saveNewAndStartProcess(
					flowEntryPublish.getProcessDefinitionId(),
					flowTaskComment,
					taskVariableData,
					masterTable,
					columnDataListResult.getData());
			}else{ //修改提交
				flowOfflineOperationService.updateAndStartProcess(masterDataId,
					flowEntryPublish.getProcessDefinitionId(),
					flowTaskComment,
					taskVariableData,
					masterTable,
					columnDataListResult.getData());
			}
		} else {
			// 如果本次请求中包含从表数据，则一同插入。
			R<Map<OnlineDatasourceRelation, List<List<ColumnData>>>> slaveDataListResult =
				onlineOperationHelper.buildSlaveDataList(datasource.getDatasourceId(), slaveData,masterDataId == null?false:true);
			if (!slaveDataListResult.isSuccess()) {
				return R.fail(slaveDataListResult.getMsg());
			}
			if (masterDataId == null) {
				flowOfflineOperationService.saveNewAndStartProcess(
					flowEntryPublish.getProcessDefinitionId(),
					flowTaskComment,
					taskVariableData,
					masterTable,
					columnDataListResult.getData(),
					slaveDataListResult.getData());
			}else{
				flowOfflineOperationService.updateAndStartProcess(
					masterDataId,
					flowEntryPublish.getProcessDefinitionId(),
					flowTaskComment,
					taskVariableData,
					masterTable,
					columnDataListResult.getData(),
					slaveDataListResult.getData());
			}
		}
		return R.success("流程启动成功");
	}

	@DisableDataFilter
	@PostMapping("/saveDraft/{processDefinitionKey}")
	@ApiOperation(notes = "流程草稿保存", value = "流程草稿保存")
	public R<Void> saveDraft(
		@PathVariable("processDefinitionKey") String processDefinitionKey,
		@RequestBody Map<String, Object> startMap,SysUser user) throws XMLStreamException {

		String errorMessage;

		FlowTaskCommentDto flowTaskCommentDto = JSONObject.parseObject((String) startMap.get("flowTaskCommentDto"), FlowTaskCommentDto.class);
		JSONObject masterData = JSONObject.parseObject((String) startMap.get("masterData"));
		JSONObject taskVariableData = JSONObject.parseObject((String) startMap.get("taskVariableData"));
		JSONObject slaveData = JSONObject.parseObject((String) startMap.get("slaveData"));
		String processInstanceId = null;
		String taskId = null;
		if(startMap.containsKey("taskId")) {
			 processInstanceId = (String) startMap.get("processInstanceId");
			 taskId = (String) startMap.get("taskId");
		}

		//主数据id
		Long masterDataId = masterData.getLong("id");

		// 1. 验证流程数据的合法性。
		R<FlowEntry> flowEntryResult = flowOperationHelper.verifyAndGetFlowEntry(processDefinitionKey);
		if (!flowEntryResult.isSuccess()) {
			return R.fail(flowEntryResult.getMsg());
		}
		// 2. 验证流程一个用户任务的合法性。
		FlowEntryPublish flowEntryPublish = flowEntryResult.getData().getMainFlowEntryPublish();
		if (!flowEntryPublish.getActiveStatus()) {
			errorMessage = "数据验证失败，当前流程发布对象已被挂起，不能启动新流程！";
			return R.fail(errorMessage);
		}
		R<TaskInfoVo> taskInfoResult = null ;
		Task task = null ;
		if(StringUtils.isNotBlank(taskId)){
			 task = flowApiService.getProcessInstanceActiveTask(processInstanceId, taskId);
			 taskInfoResult = flowOperationHelper.verifyAndGetRuntimeTaskInfo(task);
		}else{
			taskInfoResult =
				flowOperationHelper.verifyAndGetInitialTaskInfoXml(flowEntryResult.getData().getBpmnXml(),flowEntryPublish, true);
//			taskInfoResult =
//				flowOperationHelper.verifyAndGetInitialTaskInfo(flowEntryPublish, true);
		}
		if (!taskInfoResult.isSuccess()) {
			return R.fail(taskInfoResult.getMsg());
		}
		TaskInfoVo taskInfo = taskInfoResult.getData();
		// 3. 通过流程定义信息获取表单信息, 获取表单关联主表信息。
		String formName = taskInfo.getRouterName();
		QueryWrapper<OnlineForm> onlineFormQueryWrapper = new QueryWrapper<>();
		onlineFormQueryWrapper.eq("form_name", formName);
		OnlineForm onlineForm = onlineFormService.getOne(onlineFormQueryWrapper);

		R<OnlineDatasource> datasourceResult = this.verifyAndGetOnlineDatasource(onlineForm.getFormId());
		if (!datasourceResult.isSuccess()) {
			return R.fail(datasourceResult.getMsg());
		}
		OnlineDatasource datasource = datasourceResult.getData();

		Long datasourceId = datasource.getDatasourceId();

		OnlineTable masterTable = datasource.getMasterTable();

		FlowTaskComment flowTaskComment = BeanUtil.copyProperties(flowTaskCommentDto, FlowTaskComment.class);
        /*if(StringUtils.isNotBlank(taskId)){
			flowTaskComment.setTaskId(taskId);
			flowTaskComment.setProcessInstanceId(processInstanceId);
			flowTaskComment.setTaskKey(task.getTaskDefinitionKey());
			flowTaskComment.setTaskName(task.getName());
			flowTaskComment.fillWith(task);
		}*/
		slaveData = salveDataBasic(slaveData, user, StatusEnum.SAVE.getValue());
		masterData = masterDataBasic(masterData,user,StatusEnum.SAVE.getValue(),onlineForm.getFormCode(),StatusEnum.getEnum(0).getDesc()+"_"+flowTaskComment.getApprovalType());

		// 4. 为本次流程操作构建主表数据。
		R<List<ColumnData>> columnDataListResult =
			onlineOperationHelper.buildTableData(masterTable, masterData, masterDataId==null?false:true, null);
		if (!columnDataListResult.isSuccess()) {
			return R.fail(((R) columnDataListResult).getMsg());
		}

		// 5. 保存在线表单提交的数据，不启动流程和自动完成第一个用户任务。
		if (slaveData == null) {
			//主表id为空，新增主表
			if (masterDataId == null) {
				flowOfflineOperationService.saveDraft(
					flowEntryPublish.getProcessDefinitionId(),
					flowTaskComment,
					taskVariableData,
					masterTable,
					columnDataListResult.getData());
			}else{ //修改主表
				flowOfflineOperationService.updateDraft(
					flowEntryPublish.getProcessDefinitionId(),
					flowTaskComment,
					taskVariableData,
					masterTable,
					columnDataListResult.getData());
			}
		} else {
			//主数据id为空
			if (masterDataId == null) {
				// 如果本次请求中包含从表数据，则一同插入。
				R<Map<OnlineDatasourceRelation, List<List<ColumnData>>>> slaveDataListResult =
					onlineOperationHelper.buildSlaveDataList(datasource.getDatasourceId(), slaveData, false);
				if (!slaveDataListResult.isSuccess()) {
					return R.fail(slaveDataListResult.getMsg());
				}
				flowOfflineOperationService.saveDraft(
					flowEntryPublish.getProcessDefinitionId(),
					flowTaskComment,
					taskVariableData,
					masterTable,
					columnDataListResult.getData(),
					slaveDataListResult.getData());
			}else{
				flowOfflineOperationService.saveOrUpdateMasterAndSlave(masterTable,masterData,String.valueOf(masterDataId),slaveData,datasourceId,flowTaskComment);
			}
		}
		return R.success("流程草稿保存成功");
	}

	/**
	 * 流程外修改业务数据，不改变数据状态
	 * @param processDefinitionKey
	 * @param startMap
	 * @param user
	 * @return
	 * @throws XMLStreamException
	 */
	@DisableDataFilter
	@PostMapping("/updateBusinessDataOutProcess/{processDefinitionKey}")
	@ApiOperation(notes = "修改业务数据", value = "修改业务数据")
	public R<Void> updateBusinessDataOutProcess(
		@PathVariable("processDefinitionKey") String processDefinitionKey,
		@RequestBody Map<String, Object> startMap,SysUser user) throws XMLStreamException {

		String errorMessage;

		JSONObject masterData = JSONObject.parseObject((String) startMap.get("masterData"));
		JSONObject slaveData = JSONObject.parseObject((String) startMap.get("slaveData"));

		//主数据id
		Long masterDataId = masterData.getLong("id");
		if(masterDataId == null){
			return R.fail("数据不存在");
		}

		// 1. 验证流程数据的合法性。
		R<FlowEntry> flowEntryResult = flowOperationHelper.verifyAndGetFlowEntry(processDefinitionKey);
		if (!flowEntryResult.isSuccess()) {
			return R.fail(flowEntryResult.getMsg());
		}
		// 2. 验证流程一个用户任务的合法性。
		FlowEntryPublish flowEntryPublish = flowEntryResult.getData().getMainFlowEntryPublish();
		if (!flowEntryPublish.getActiveStatus()) {
			errorMessage = "数据验证失败，当前流程发布对象已被挂起，不能启动新流程！";
			return R.fail(errorMessage);
		}
		R<TaskInfoVo> taskInfoResult = flowOperationHelper.verifyAndGetInitialTaskInfoXml(flowEntryResult.getData().getBpmnXml(),flowEntryPublish, true);
		if (!taskInfoResult.isSuccess()) {
			return R.fail(taskInfoResult.getMsg());
		}
		TaskInfoVo taskInfo = taskInfoResult.getData();
		// 3. 通过流程定义信息获取表单信息, 获取表单关联主表信息。
		String formName = taskInfo.getRouterName();
		QueryWrapper<OnlineForm> onlineFormQueryWrapper = new QueryWrapper<>();
		onlineFormQueryWrapper.eq("form_name", formName);
		OnlineForm onlineForm = onlineFormService.getOne(onlineFormQueryWrapper);

		R<OnlineDatasource> datasourceResult = this.verifyAndGetOnlineDatasource(onlineForm.getFormId());
		if (!datasourceResult.isSuccess()) {
			return R.fail(datasourceResult.getMsg());
		}
		OnlineDatasource datasource = datasourceResult.getData();

		Long datasourceId = datasource.getDatasourceId();

		OnlineTable masterTable = datasource.getMasterTable();

		slaveData = salveDataBasic(slaveData, user, StatusEnum.UPDATE.getValue());
		masterData = masterDataBasic(masterData,user,StatusEnum.UPDATE.getValue(),onlineForm.getFormCode(),"");

		// 4. 为本次流程操作构建主表数据。
		R<List<ColumnData>> columnDataListResult =
			onlineOperationHelper.buildTableData(masterTable, masterData, masterDataId==null?false:true, null);
		if (!columnDataListResult.isSuccess()) {
			return R.fail(((R) columnDataListResult).getMsg());
		}

		// 5. 保存在线表单提交的数据，不启动流程和自动完成第一个用户任务。
		if (slaveData == null) {
			//修改主表
			flowOfflineOperationService.updateDraft(
				flowEntryPublish.getProcessDefinitionId(),
				null,
				null,
				masterTable,
				columnDataListResult.getData());
		} else {
			//主数据id为空
			flowOfflineOperationService.saveOrUpdateMasterAndSlave(masterTable,masterData,String.valueOf(masterDataId),slaveData,datasourceId,null);
		}
		return R.success("修改成功");
	}

//	@DisableDataFilter
//	@PostMapping("/updateDraft/{processDefinitionKey}")
//	@ApiOperation(notes = "流程草稿修改", value = "流程草稿修改")
//	public R<Void> updateDraft(@PathVariable("processDefinitionKey") String processDefinitionKey,
//							   @RequestBody Map<String, Object> startMap,SysUser user) throws XMLStreamException {
//		String errorMessage;
//
//		FlowTaskCommentDto flowTaskCommentDto = JSONObject.parseObject((String) startMap.get("flowTaskCommentDto"), FlowTaskCommentDto.class);
//		JSONObject masterData = JSONObject.parseObject((String) startMap.get("masterData"));
//		JSONObject taskVariableData = JSONObject.parseObject((String) startMap.get("taskVariableData"));
//		JSONObject slaveData = JSONObject.parseObject((String) startMap.get("slaveData"));
//
//		// 1. 验证流程数据的合法性。
//		R<FlowEntry> flowEntryResult = flowOperationHelper.verifyAndGetFlowEntry(processDefinitionKey);
//		if (!flowEntryResult.isSuccess()) {
//			return R.fail(flowEntryResult.getMsg());
//		}
//
//		// 2. 验证流程一个用户任务的合法性。
//		FlowEntryPublish flowEntryPublish = flowEntryResult.getData().getMainFlowEntryPublish();
//		if (!flowEntryPublish.getActiveStatus()) {
//			errorMessage = "数据验证失败，当前流程发布对象已被挂起，不能启动新流程！";
//			return R.fail(errorMessage);
//		}
//		R<TaskInfoVo> taskInfoResult =
//			flowOperationHelper.verifyAndGetInitialTaskInfoXml(flowEntryResult.getData().getBpmnXml(),flowEntryPublish, true);
//		if (!taskInfoResult.isSuccess()) {
//			return R.fail(taskInfoResult.getMsg());
//		}
//		TaskInfoVo taskInfo = taskInfoResult.getData();
//
//		// 3. 通过流程定义信息获取表单信息, 获取表单关联主表信息。
//		String formName = taskInfo.getRouterName();
//		QueryWrapper<OnlineForm> onlineFormQueryWrapper = new QueryWrapper<>();
//		onlineFormQueryWrapper.eq("form_name", formName);
//		OnlineForm onlineForm = onlineFormService.getOne(onlineFormQueryWrapper);
//
//		R<OnlineDatasource> datasourceResult = this.verifyAndGetOnlineDatasource(onlineForm.getFormId());
//		if (!datasourceResult.isSuccess()) {
//			return R.fail(datasourceResult.getMsg());
//		}
//		OnlineDatasource datasource = datasourceResult.getData();
//
//		OnlineTable masterTable = datasource.getMasterTable();
//
//		FlowTaskComment flowTaskComment = BeanUtil.copyProperties(flowTaskCommentDto, FlowTaskComment.class);
//		slaveData = salveDataBasic(slaveData, user, StatusEnum.SAVE.getValue());
//		masterData = masterDataBasic(masterData,user,StatusEnum.SAVE.getValue(),onlineForm.getFormCode(),StatusEnum.getEnum(0).getDesc()+"_"+flowTaskComment.getApprovalType());
//
//		// 4. 为本次流程操作构建数据。
//		R<List<ColumnData>> columnDataListResult =
//			onlineOperationHelper.buildTableData(masterTable, masterData, true, null);
//		if (!columnDataListResult.isSuccess()) {
//			return R.fail(((R) columnDataListResult).getMsg());
//		}
//
//		// 5. 修改在线表单提交的数据，不启动流程和自动完成第一个用户任务。
//		if (slaveData == null) {
//			flowOfflineOperationService.updateDraft(
//				flowEntryPublish.getProcessDefinitionId(),
//				flowTaskComment,
//				taskVariableData,
//				masterTable,
//				columnDataListResult.getData());
//		} else {
//			// 如果本次请求中包含从表数据，则一同修改。
//			R<Map<OnlineDatasourceRelation, List<List<ColumnData>>>> slaveDataListResult =
//				onlineOperationHelper.buildSlaveDataList(datasource.getDatasourceId(), slaveData,true);
//			if (!slaveDataListResult.isSuccess()) {
//				return R.fail(slaveDataListResult.getMsg());
//			}
//			flowOfflineOperationService.updateDraft(
//				flowEntryPublish.getProcessDefinitionId(),
//				flowTaskComment,
//				taskVariableData,
//				masterTable,
//				columnDataListResult.getData(),
//				slaveDataListResult.getData());
//		}
//
//		return R.success("流程草稿修改成功");
//	}


	/**
	 * 提交流程的用户任务。
	 * 该接口无需数据权限过滤，因此用DisableDataFilter注解标注。如果当前系统没有支持数据权限过滤，该注解不会有任何影响。
	 *

	 * @return 应答结果对象。
	 */
	@DisableDataFilter
	@PostMapping("/submitUserTask")
	@ApiOperation(notes = "提交流程", value = "提交流程")
	public R<Void> submitUserTask(
		@RequestBody Map<String, Object> startMap,
		SysUser user) {
		String processInstanceId = (String) startMap.get("processInstanceId");
		String taskId = (String) startMap.get("taskId");
		FlowTaskCommentDto flowTaskCommentDto = JSONObject.parseObject((String) startMap.get("flowTaskCommentDto"), FlowTaskCommentDto.class);
		JSONObject masterData = JSONObject.parseObject((String) startMap.get("masterData"));
		JSONObject taskVariableData = JSONObject.parseObject((String) startMap.get("taskVariableData"));
		JSONObject slaveData = JSONObject.parseObject((String) startMap.get("slaveData"));
		String errorMessage;
		// 验证流程任务的合法性。
		Task task = flowApiService.getProcessInstanceActiveTask(processInstanceId, taskId);
		R<TaskInfoVo> taskInfoResult = flowOperationHelper.verifyAndGetRuntimeTaskInfo(task);
		if (!taskInfoResult.isSuccess()) {
			return R.fail(taskInfoResult.getMsg());
		}
		TaskInfoVo taskInfo = taskInfoResult.getData();
		// 验证在线表单及其关联数据源的合法性。
		String formName = taskInfo.getRouterName();
		QueryWrapper<OnlineForm> onlineFormQueryWrapper = new QueryWrapper<>();
		onlineFormQueryWrapper.eq("form_name", formName);
		OnlineForm onlineForm = onlineFormService.getOne(onlineFormQueryWrapper);

		R<OnlineDatasource> datasourceResult = this.verifyAndGetOnlineDatasource(onlineForm.getFormId());
		if (!datasourceResult.isSuccess()) {
			return R.fail(datasourceResult.getMsg());
		}
		R assigneeVerifyResult = flowApiService.verifyAssigneeOrCandidateAndClaim(task);
		if (!assigneeVerifyResult.isSuccess()) {
			return R.fail(assigneeVerifyResult.getMsg());
		}
		OnlineDatasource datasource = datasourceResult.getData();
		OnlineTable masterTable = datasource.getMasterTable();
		Long datasourceId = datasource.getDatasourceId();
		//主表数据主键id
		String dataId = task.getBusinessKey();
		//若为新设备小件立项
		if ("en_new_device_info".equals(masterTable.getTableName())){
			String project_no = masterData.getString("project_no");
			//验证远程测试是否完成
			R<String> remoteTestMsg = onlineOperationHelper.validateRemoteTest(datasource.getDatasourceId(),dataId,slaveData,task,project_no);
			if (!remoteTestMsg.isSuccess()) {
				return R.fail(remoteTestMsg.getMsg());
			}
		}
		FlowTaskComment flowTaskComment = BeanUtil.copyProperties(flowTaskCommentDto, FlowTaskComment.class);
		slaveData = salveDataBasic(slaveData, user, StatusEnum.PRI_ACCESS.getValue());
		masterData = masterDataBasic(masterData,user,StatusEnum.PRI_ACCESS.getValue(),onlineForm.getFormCode(),flowTaskComment.getTaskName()+"_"+flowTaskComment.getApprovalType());
		if (StrUtil.isBlank(dataId)) {
			return this.submitNewTask(processInstanceId, taskId,
				flowTaskComment, taskVariableData, masterTable, masterData, slaveData, datasourceId);
		}
		try {
			if (StrUtil.equals(flowTaskComment.getApprovalType(), FlowApprovalType.TRANSFER)) {
				if (StrUtil.isBlank(flowTaskComment.getDelegateAssginee())) {
					errorMessage = "数据验证失败，加签或转办任务指派人不能为空！！";
					return R.fail(errorMessage);
				}
			}
			flowOfflineOperationService.updateAndTakeTask(
				task, flowTaskComment, taskVariableData, masterTable, masterData, dataId, slaveData, datasourceId);
		} catch (FlowOperationException e) {
			log.error("Failed to call [FlowOnlineOperationService.updateAndTakeTask]", e);
			return R.fail(e.getMessage());
		}
		return R.data(null);
	}

	/**
	 * 获取当前流程实例的详情数据。包括主表数据、一对一从表数据、一对多从表数据列表等。
	 * 该接口无需数据权限过滤，因此用DisableDataFilter注解标注。如果当前系统没有支持数据权限过滤，该注解不会有任何影响。
	 *
	 * @param processInstanceId 当前运行时的流程实例Id。
	 * @param taskId            流程任务Id。
	 * @return 当前流程实例的详情数据。
	 */
	@DisableDataFilter
	@GetMapping("/viewUserTask")
	@ApiOperation(notes = "当前流程实例的详情数据", value = "当前流程实例的详情数据")
	public R<JSONObject> viewUserTask(@RequestParam String processInstanceId, @RequestParam String taskId) {
		String errorMessage;
		// 验证流程任务的合法性。
		Task task = flowApiService.getProcessInstanceActiveTask(processInstanceId, taskId);
		// 如果业务主数据为空，则直接返回。
		if (StrUtil.isBlank(task.getBusinessKey())) {
			return R.data(null);
		}
		R<TaskInfoVo> taskInfoResult = flowOperationHelper.verifyAndGetRuntimeTaskInfo(task);
		if (!taskInfoResult.isSuccess()) {
			return R.fail(taskInfoResult.getMsg());
		}
		TaskInfoVo taskInfo = taskInfoResult.getData();
		// 验证在线表单及其关联数据源的合法性。
		String formName = taskInfo.getRouterName();
		QueryWrapper<OnlineForm> onlineFormQueryWrapper = new QueryWrapper<>();
		onlineFormQueryWrapper.eq("form_name", formName);
		OnlineForm onlineForm = onlineFormService.getOne(onlineFormQueryWrapper);

		R<OnlineDatasource> datasourceResult = this.verifyAndGetOnlineDatasource(onlineForm.getFormId());
		if (!datasourceResult.isSuccess()) {
			return R.fail(datasourceResult.getMsg());
		}
		OnlineDatasource datasource = datasourceResult.getData();
		R<List<OnlineDatasourceRelation>> relationListResult =
			onlineOperationHelper.verifyAndGetRelationList(datasource.getDatasourceId(), null);
		if (!relationListResult.isSuccess()) {
			return R.fail(relationListResult.getMsg());
		}
		JSONObject jsonData = this.buildUserTaskData(
			task.getBusinessKey(), datasource.getMasterTable(), relationListResult.getData());
		return R.data(jsonData);
	}

	/**
	 * 获取已经结束的流程实例的详情数据。包括主表数据、一对一从表数据、一对多从表数据列表等。
	 * 该接口无需数据权限过滤，因此用DisableDataFilter注解标注。如果当前系统没有支持数据权限过滤，该注解不会有任何影响。
	 *
	 * @param processInstanceId 历史流程实例Id。
	 * @param taskId            历史任务Id。如果该值为null，仅有发起人可以查看当前流程数据，否则只有任务的指派人才能查看。
	 * @return 历史流程实例的详情数据。
	 */
	@DisableDataFilter
	@GetMapping("/viewHistoricProcessInstance")
	@ApiOperation(notes = "历史流程实例的详情数据", value = "历史流程实例的详情数据")
	public R<JSONObject> viewHistoricProcessInstance(
		@RequestParam String processInstanceId, @RequestParam(required = false) String taskId) {
		String errorMessage;
		// 验证流程实例的合法性。
		HistoricProcessInstance instance = flowApiService.getHistoricProcessInstance(processInstanceId);
		if (instance == null) {
			errorMessage = "数据验证失败，指定的流程实例Id并不存在，请刷新后重试！";
			return R.fail(errorMessage);
		}
		String loginName = SecureUtil.getUserAccount();
		if (StrUtil.isBlank(taskId)) {
			/*if (!StrUtil.equals(loginName, instance.getStartUserId())) {
				errorMessage = "数据验证失败，指定历史流程的发起人与当前用户不匹配！";
				return R.fail(errorMessage);
			}*/
		} else {
			HistoricTaskInstance taskInstance = flowApiService.getHistoricTaskInstance(processInstanceId, taskId);
			if (taskInstance == null) {
				errorMessage = "数据验证失败，指定的任务Id并不存在，请刷新后重试！";
				return R.fail(errorMessage);
			}
			if (!StrUtil.equals(loginName, taskInstance.getAssignee())) {
				errorMessage = "数据验证失败，历史任务的指派人与当前用户不匹配！";
				return R.fail(errorMessage);
			}
		}
		if (StrUtil.isBlank(instance.getBusinessKey())) {
			// 对于没有提交过任何用户任务的场景，可直接返回空数据。
			return R.data(new JSONObject());
		}
		FlowEntryPublish flowEntryPublish =
			flowEntryService.getFlowEntryPublishList(CollUtil.newHashSet(instance.getProcessDefinitionId())).get(0);
		TaskInfoVo taskInfoVo = JSON.parseObject(flowEntryPublish.getInitTaskInfo(), TaskInfoVo.class);
		// 验证在线表单及其关联数据源的合法性。
		String formName = taskInfoVo.getRouterName();
		QueryWrapper<OnlineForm> onlineFormQueryWrapper = new QueryWrapper<>();
		onlineFormQueryWrapper.eq("form_name", formName);
		OnlineForm onlineForm = onlineFormService.getOne(onlineFormQueryWrapper);

		R<OnlineDatasource> datasourceResult = this.verifyAndGetOnlineDatasource(onlineForm.getFormId());
		if (!datasourceResult.isSuccess()) {
			return R.fail(datasourceResult.getMsg());
		}
		OnlineDatasource datasource = datasourceResult.getData();
		R<List<OnlineDatasourceRelation>> relationListResult =
			onlineOperationHelper.verifyAndGetRelationList(datasource.getDatasourceId(), null);
		if (!relationListResult.isSuccess()) {
			return R.fail(relationListResult.getMsg());
		}
		JSONObject jsonData = this.buildUserTaskData(
			instance.getBusinessKey(), datasource.getMasterTable(), relationListResult.getData());
		return R.data(jsonData);
	}


	/**(用于只读与查看)
	 * 获取已经结束的流程实例的详情数据。包括主表数据、一对一从表数据、一对多从表数据列表等。
	 * 该接口无需数据权限过滤，因此用DisableDataFilter注解标注。如果当前系统没有支持数据权限过滤，该注解不会有任何影响。
	 *	@author wuning
	 * 	@date: 2022/9/1 13:52
	 * @param processInstanceId 历史流程实例Id。
	 * @param taskId            历史任务Id。如果该值为null，仅有发起人可以查看当前流程数据，否则只有任务的指派人才能查看。
	 * @return 历史流程实例的详情数据。
	 */
	@DisableDataFilter
	@GetMapping("/viewHistoricProcessInstanceRead")
	@ApiOperation(notes = "历史流程实例的详情数据(用于只读与查看)", value = "历史流程实例的详情数据(用于只读与查看)")
	public R<JSONObject> viewHistoricProcessInstanceRead(
		@RequestParam String processInstanceId, @RequestParam(required = false) String taskId) {
		String errorMessage;
		// 验证流程实例的合法性。
		HistoricProcessInstance instance = flowApiService.getHistoricProcessInstance(processInstanceId);
		if (instance == null) {
			errorMessage = "数据验证失败，指定的流程实例Id并不存在，请刷新后重试！";
			return R.fail(errorMessage);
		}
		if (!StrUtil.isBlank(taskId)) {
			HistoricTaskInstance taskInstance = flowApiService.getHistoricTaskInstance(processInstanceId, taskId);
			if (taskInstance == null) {
				errorMessage = "数据验证失败，指定的任务Id并不存在，请刷新后重试！";
				return R.fail(errorMessage);
			}
		}
		if (StrUtil.isBlank(instance.getBusinessKey())) {
			// 对于没有提交过任何用户任务的场景，可直接返回空数据。
			return R.data(null);
		}
		TaskInfoVo taskInfoVo = JSON.parseObject(flowEntryService.getFlowEntryPublishList(CollUtil.newHashSet(instance.getProcessDefinitionId())).get(0).getInitTaskInfo(), TaskInfoVo.class);
		// 验证在线表单及其关联数据源的合法性。
		QueryWrapper<OnlineForm> onlineFormQueryWrapper = new QueryWrapper<>();
		onlineFormQueryWrapper.eq("form_name", taskInfoVo.getRouterName());
		R<OnlineDatasource> datasourceResult = this.verifyAndGetOnlineDatasource(onlineFormService.getOne(onlineFormQueryWrapper).getFormId());
		if (!datasourceResult.isSuccess()) {
			return R.fail(datasourceResult.getMsg());
		}
		OnlineDatasource datasource = datasourceResult.getData();
		R<List<OnlineDatasourceRelation>> relationListResult =
			onlineOperationHelper.verifyAndGetRelationList(datasource.getDatasourceId(), null);
		if (!relationListResult.isSuccess()) {
			return R.fail(relationListResult.getMsg());
		}
		JSONObject jsonData = this.buildUserTaskData(
			instance.getBusinessKey(), datasource.getMasterTable(), relationListResult.getData());
		return R.data(jsonData);
	}
	/**
	 *  根据业务主键查询流程实例数据
	 * @param processDefinitionKey
	 * @param businessKey
	 * @return
	 */
	@DisableDataFilter
	@GetMapping("/viewProcessInstanceByBusinessKey")
	@ApiOperation(notes = "根据业务主键查询流程实例数据", value = "根据业务主键查询流程实例数据")
	public R<JSONObject> viewProcessInstanceByBusinessKey(
		@RequestParam("processDefinitionKey") String processDefinitionKey,
		@RequestParam("dataId") String businessKey,SysUser user) {
		try {
			// 1. 验证流程数据的合法性。
			R<FlowEntry> flowEntryResult = flowOperationHelper.verifyAndGetFlowEntry(processDefinitionKey);
			if (!flowEntryResult.isSuccess()) {
				return R.fail(flowEntryResult.getMsg());
			}

			// 查询历史任务是否存在
			//HistoricProcessInstanceQuery queryHis =historyService.createHistoricProcessInstanceQuery();
			HistoricTaskInstanceQuery queryHis = historyService.createHistoricTaskInstanceQuery().processInstanceBusinessKey(businessKey).processDefinitionKey(processDefinitionKey);
			//queryHis.processDefinitionKey(processDefinitionKey).processInstanceBusinessKey(businessKey);
			List<HistoricTaskInstance> instanceList = queryHis.list();
			if(instanceList != null && instanceList.size()>0){
				HistoricTaskInstance instance = instanceList.get(0);
				R<JSONObject> data = viewHistoricProcessInstanceRead(instance.getProcessInstanceId(),instance.getId());
				if(data != null && data.isSuccess()){
					JSONObject re = data.getData();
					re.put("processInstanceId",instance.getProcessInstanceId());
					re.put("processDefinitionId",instance.getProcessDefinitionId());
					return R.data(re);
				}else{
					return data;
				}

			}
			//历史和运行都不存在， 查询业务草稿数据
			Object data= draftDetail(processDefinitionKey,businessKey,user).getData();
			if(data != null){
				return R.data(JSONObject.parseObject(JSONObject.toJSONString(data)));
			}
			return R.data(null);
		}catch (Exception e){
			log.error("－－－－根据业务主键查询流程数据异常－－－：{}", e);
		}
		return null;
	}
	/**
	 * 工作流工单列表。
	 *
	 * @param processDefinitionKey 流程标识名。
	 * @param flowWorkOrder        过滤对象。
	 * @param query                分页参数。
	 * @return 查询结果。
	 */
	@PostMapping("/listWorkOrder/{processDefinitionKey}")
	@ApiOperation(notes = "工作流工单列表", value = "工作流工单列表")
	public R<IPage<FlowWorkOrderVo>> listWorkOrder(@PathVariable("processDefinitionKey") String processDefinitionKey,
												   @RequestBody FlowWorkOrder flowWorkOrder,
												   Query query) {

		flowWorkOrder.setProcessDefinitionKey(processDefinitionKey);
		//flowWorkOrder.setCreateUserId(SecureUtil.getUserId());
		IPage<FlowWorkOrder> pages = flowWorkOrderService.page(Condition.getPage(query), Condition.getQueryWrapper(flowWorkOrder));

		R<Void> responseResult = this.makeWorkOrderTaskInfo(FlowWorkOrderWrapper.build().listVO(pages.getRecords()));
		if (!responseResult.isSuccess()) {
			return R.fail(responseResult.getMsg());
		}
		IPage<FlowWorkOrderVo> re = com.chongchong.flow.online.wrapper.FlowWorkOrderWrapper.build().pageVO(pages);
		List<FlowWorkOrderVo> listVo = re.getRecords();
		/*for(FlowWorkOrderVo vo : listVo){
			vo.setMasterData(viewHistoricProcessInstance(vo.getProcessInstanceId(),null).getData());
		}
		re.setRecords(listVo);*/
		return R.data(re);
	}

	/**
	 * 列表
	 *
	 * @param processDefinitionKey
	 * @param filterList
	 * @param query
	 * @return
	 */
	@PostMapping("/listMasterData/{processDefinitionKey}")
	@ApiImplicitParams({
		@ApiImplicitParam(name = "processDefinitionKey", value = "form_code节点", paramType = "path", dataType = "string"),
	})
	@ApiOperation(notes = "工作实例列表", value = "工作实例列表")
	public R<IPage<Map<String, Object>>> listMasterData(@PathVariable("processDefinitionKey") String processDefinitionKey,
														@RequestParam(required = false) String definitionKey,
														@RequestBody(required = false) List<OnlineFilterDto> filterList, Query query, SysUser user) {

		// 验证在线表单及其关联数据源的合法性。
		QueryWrapper<OnlineForm> onlineFormQueryWrapper = new QueryWrapper<>();
		onlineFormQueryWrapper.eq("form_code", processDefinitionKey);
		OnlineForm onlineForm = onlineFormService.getOne(onlineFormQueryWrapper);

		R<OnlineDatasource> datasourceResult = this.verifyAndGetOnlineDatasource(onlineForm.getFormId());
		if (!datasourceResult.isSuccess()) {
			return R.fail(datasourceResult.getMsg());
		}
		OnlineDatasource datasource = datasourceResult.getData();
		R<List<OnlineDatasourceRelation>> relationListResult =
			onlineOperationHelper.verifyAndGetRelationList(datasource.getDatasourceId(), null);
		if (!relationListResult.isSuccess()) {
			return R.fail(relationListResult.getMsg());
		}

		List<OnlineDatasourceRelation> allRelationList = relationListResult.getData();
		// 2. 验证数据过滤对象中的表名和字段，确保没有sql注入。
		R<Void> filterDtoListResult = this.verifyFilterDtoList(filterList);
		if (!filterDtoListResult.isSuccess()) {
			return R.fail(filterDtoListResult.getMsg());
		}

		if(filterList == null){
			filterList = new ArrayList<>();
		}
			//添加表单条件
			OnlineFilterDto ofd = new OnlineFilterDto();
			ofd.setColumnName("form_code");
			ofd.setColumnValue(processDefinitionKey);
			ofd.setTableName(datasource.getMasterTable().getTableName());
			filterList.add(ofd);
		IPage<Map<String, Object>> page = buildMasterData(datasource.getMasterTable(), allRelationList, filterList, datasource.getMasterTable().getTableName()+".create_time desc ", query,definitionKey);
		return R.data(page);
	}
	/**
	 * 根据type工作实例列表
	 *
	 * @param processDefinitionKey
	 * @param filterList
	 * @param query
	 * @return
	 */
	@PostMapping("/listMasterDataByType/{processDefinitionKey}/{type}")
	@ApiImplicitParams({
		@ApiImplicitParam(name = "processDefinitionKey", value = "processDefinitionKey节点", paramType = "path", dataType = "string"),
		@ApiImplicitParam(name = "type", value = "type为0为添加条件节点，1为不添加条件节点，", defaultValue="0",paramType = "path", dataType = "int")
	})
	@ApiOperation(notes = "根据type工作实例列表", value = "根据type工作实例列表")
	public R<IPage<Map<String, Object>>> listMasterData(@PathVariable("processDefinitionKey") String processDefinitionKey,
														@PathVariable("type") int type,
														@RequestParam(required = false) String definitionKey,
														@RequestBody(required = false) List<OnlineFilterDto> filterList, Query query, SysUser user) {

		if (StrUtil.isBlank(processDefinitionKey)) {
			return R.fail("请传入formCode参数");
		}
		Set<String> collect = Arrays.stream(processDefinitionKey.split(",")).collect(Collectors.toSet());
		String s = collect.stream().findFirst().get();
		// 验证在线表单及其关联数据源的合法性。
		QueryWrapper<OnlineForm> onlineFormQueryWrapper = new QueryWrapper<>();
		onlineFormQueryWrapper.eq("form_code", s);
		OnlineForm onlineForm = onlineFormService.getOne(onlineFormQueryWrapper);

		R<OnlineDatasource> datasourceResult = this.verifyAndGetOnlineDatasource(onlineForm.getFormId());
		if (!datasourceResult.isSuccess()) {
			return R.fail(datasourceResult.getMsg());
		}
		OnlineDatasource datasource = datasourceResult.getData();
		R<List<OnlineDatasourceRelation>> relationListResult =
			onlineOperationHelper.verifyAndGetRelationList(datasource.getDatasourceId(), null);
		if (!relationListResult.isSuccess()) {
			return R.fail(relationListResult.getMsg());
		}

		List<OnlineDatasourceRelation> allRelationList = relationListResult.getData();
		// 2. 验证数据过滤对象中的表名和字段，确保没有sql注入。
		R<Void> filterDtoListResult = this.verifyFilterDtoList(filterList);
		if (!filterDtoListResult.isSuccess()) {
			return R.fail(filterDtoListResult.getMsg());
		}

		if(filterList == null){
			filterList = new ArrayList<>();
		}
		if(type==0){
			//添加表单条件
			OnlineFilterDto ofd = new OnlineFilterDto();
			ofd.setColumnName("form_code");
			ofd.setColumnValueList(Arrays.stream(processDefinitionKey.split(",")).collect(Collectors.toSet()));
			ofd.setFilterType(FieldFilterType.IN_LIST_FILTER);
			ofd.setTableName(datasource.getMasterTable().getTableName());
			filterList.add(ofd);
		}
		IPage<Map<String, Object>> page = buildMasterData(datasource.getMasterTable(), allRelationList, filterList, datasource.getMasterTable().getTableName()+".create_time desc ", query,definitionKey);
		return R.data(page);
	}
	/**
	 * 根据流程标识和任务名称查询业务数据。
	 *
	 * @param processDefinitionKey  流程标识。
	 * @param taskName              任务名称 。
	 * @return 返回当前用户待办的任务列表。如果指定流程标识，则仅返回该流程的待办任务列表。
	 */
	@PostMapping("/listRuntimeTaskByTaskName")
	@ApiOperation(notes = "根据流程标识和任务名称查询业务数据",value = "根据流程标识和任务名称查询业务数据")
	public R<List<FlowTaskVo>> listRuntimeTaskByTaskName(@RequestParam String processDefinitionKey,
											   @RequestParam String taskName,
											   @RequestBody(required = false) List<OnlineFilterDto> filterList) throws ParseException {
		try {
			// 1. 验证流程数据的合法性。
			R<FlowEntry> flowEntryResult = flowOperationHelper.verifyAndGetFlowEntry(processDefinitionKey);
			if (!flowEntryResult.isSuccess()) {
				return R.fail(flowEntryResult.getMsg());
			}
			//根据流程定义标识和任务名称查询任务
			List<Task> taskList = null;
			if(StringUtils.isNotBlank(taskName)) {
				taskList = flowApiService.getTaskListByTaskNameList(processDefinitionKey, Func.toStrList(",",taskName));
			}
			if(taskList.isEmpty()){
				return R.data(null);
			}
			List<FlowTaskVo> flowTaskVoList = flowApiService.convertToFlowTaskList(taskList);
			if(flowTaskVoList == null || flowTaskVoList.size()== 0){
				return  R.data(null);
			}
			Set<Object> bList = flowTaskVoList.stream().map(vo->vo.getBusinessKey()).collect(Collectors.toSet());



			//List<OnlineFilterDto>	filterList = new ArrayList<>();
			if(filterList == null){
				filterList = new ArrayList<>();
			}
			//filterList.stream().forEach(f->f.setTableName(datasource.getMasterTable().getTableName()));
			//添加表单条件
			String formName =JSONObject.parseObject(flowTaskVoList.get(0).getTaskFormKey()).getString("routerName");
			QueryWrapper<OnlineForm> onlineFormQueryWrapper = new QueryWrapper<>();
			onlineFormQueryWrapper.eq("form_name", formName);
			OnlineForm onlineForm = onlineFormService.getOne(onlineFormQueryWrapper);
			R<OnlineDatasource> datasourceResult = this.verifyAndGetOnlineDatasource(onlineForm.getFormId());
			if (!datasourceResult.isSuccess()) {
				return R.fail(datasourceResult.getMsg());
			}
			OnlineDatasource datasource = datasourceResult.getData();

			OnlineTable masterTable = datasource.getMasterTable();
			R<List<OnlineDatasourceRelation>> relationListResult =
				onlineOperationHelper.verifyAndGetRelationList(datasource.getDatasourceId(), null);
			if (!relationListResult.isSuccess()) {
				return R.fail(relationListResult.getMsg());
			}
			//所有关联关系
			List<OnlineDatasourceRelation> allRelationList = relationListResult.getData();
			List<OnlineDatasourceRelation> oneToOneRelationList = allRelationList.stream()
				.filter(r -> r.getRelationType().equals(RelationType.ONE_TO_ONE)).collect(Collectors.toList());


			OnlineFilterDto ofd = new OnlineFilterDto();
			ofd.setTableName(datasource.getMasterTable().getTableName());
			ofd.setFilterType(FieldFilterType.IN_LIST_FILTER);
			ofd.setColumnValueList(bList);
			ofd.setColumnName(datasource.getMasterTable().getPrimaryKeyColumn().getColumnName());
			filterList.add(ofd);
			List<Map<String, Object>> masterDataList = onlineOperationService.getMasterDataList(masterTable,oneToOneRelationList,allRelationList,filterList," create_time desc ");
			//Map<String,Map<String,Object>> map =  masterDataList.stream().map(map->String.valueOf(map.get(datasource.getMasterTable().getPrimaryKeyColumn().getColumnName()))).collect(Collectors.toList());
			Map<String,Map<String,Object>> taskMap = masterDataList.stream().collect(Collectors.toMap(map-> String.valueOf(map.get(datasource.getMasterTable()
				.getPrimaryKeyColumn().getColumnName())), Function.identity(), (task1, task2) -> task2));

			flowTaskVoList.forEach(o->{
              o.setMasterData(taskMap.get(o.getBusinessKey()));
			});
			//过滤掉masterData为空的值
			List<FlowTaskVo> re = flowTaskVoList.stream().filter(f->f.getMasterData()!=null ).filter( CommonUtil.distinctByKey(f->f.getBusinessKey())).collect(Collectors.toList());
			return R.data(re);
		}catch (Exception e){
			e.printStackTrace();
		}
		return R.status(Boolean.FALSE);
	}

	/**
	 * 根据流程标识和业务条件查询业务数据。
	 *
	 * @param formCode  流程标识。
	 * @param formCode              任务名称 。
	 * @return 返回当前用户待办的任务列表。如果指定流程标识，则仅返回该流程的待办任务列表。
	 */
	@PostMapping("/listBussinessData")
	@ApiOperation(notes = "根据流程标识和业务条件查询业务数据",value = "根据流程标识和业务条件查询业务数据")
	public R<List<Map<String, Object>>> listBussinessData(@RequestParam String formCode,
											   @RequestBody(required = false) List<OnlineFilterDto> filterList) throws ParseException {
		try {

			if(filterList == null){
				filterList = new ArrayList<>();
			}
			//filterList.stream().forEach(f->f.setTableName(datasource.getMasterTable().getTableName()));
			//添加表单条件
			QueryWrapper<OnlineForm> onlineFormQueryWrapper = new QueryWrapper<>();
			onlineFormQueryWrapper.eq("form_code", formCode);
			OnlineForm onlineForm = onlineFormService.getOne(onlineFormQueryWrapper);
			R<OnlineDatasource> datasourceResult = this.verifyAndGetOnlineDatasource(onlineForm.getFormId());
			if (!datasourceResult.isSuccess()) {
				return R.fail(datasourceResult.getMsg());
			}
			OnlineDatasource datasource = datasourceResult.getData();

			OnlineTable masterTable = datasource.getMasterTable();
			R<List<OnlineDatasourceRelation>> relationListResult =
				onlineOperationHelper.verifyAndGetRelationList(datasource.getDatasourceId(), null);
			if (!relationListResult.isSuccess()) {
				return R.fail(relationListResult.getMsg());
			}
			//所有关联关系
			List<OnlineDatasourceRelation> allRelationList = relationListResult.getData();
			List<OnlineDatasourceRelation> oneToOneRelationList = allRelationList.stream()
				.filter(r -> r.getRelationType().equals(RelationType.ONE_TO_ONE)).collect(Collectors.toList());
			List<Map<String, Object>> masterDataList = onlineOperationService.getMasterDataList(masterTable,oneToOneRelationList,allRelationList,filterList," create_time desc ");
			return R.data(masterDataList);
		}catch (Exception e){
			e.printStackTrace();
		}
		return R.status(Boolean.FALSE);
	}
	/**
	 * 草稿详情
	 *
	 * @param processDefinitionKey
	 * @param dataId
	 * @return
	 */
	@PostMapping("/draftDetail/{processDefinitionKey}")
	@ApiOperation(notes = "草稿详情", value = "草稿详情")
	public R<Object> draftDetail(@PathVariable("processDefinitionKey") String processDefinitionKey,
														@RequestParam String dataId,  SysUser user) {

		// 验证在线表单及其关联数据源的合法性。
		QueryWrapper<OnlineForm> onlineFormQueryWrapper = new QueryWrapper<>();
		onlineFormQueryWrapper.eq("form_code", processDefinitionKey);
		OnlineForm onlineForm = onlineFormService.getOne(onlineFormQueryWrapper);

		R<OnlineDatasource> datasourceResult = this.verifyAndGetOnlineDatasource(onlineForm.getFormId());
		if (!datasourceResult.isSuccess()) {
			return R.fail(datasourceResult.getMsg());
		}
		OnlineDatasource datasource = datasourceResult.getData();
		R<List<OnlineDatasourceRelation>> relationListResult =
			onlineOperationHelper.verifyAndGetRelationList(datasource.getDatasourceId(), null);
		if (!relationListResult.isSuccess()) {
			return R.fail(relationListResult.getMsg());
		}

		List<OnlineDatasourceRelation> allRelationList = relationListResult.getData();

		List<OnlineDatasourceRelation> oneToOneRelationList = allRelationList.stream()
			.filter(r -> r.getRelationType().equals(RelationType.ONE_TO_ONE)).collect(Collectors.toList());
		Map<String, Object> masterData = onlineOperationService.getMasterData(datasource.getMasterTable(),oneToOneRelationList,allRelationList, dataId);
        JSONObject obj = new JSONObject();
		allRelationList.stream().forEach(o->{
			if (o.getRelationType() == RelationType.ONE_TO_MANY){
				List<OnlineFilterDto> filterList = new ArrayList<>();
				OnlineFilterDto ofd = new OnlineFilterDto();
				ofd.setColumnName(onlineColumnService.getById(o.getSlaveColumnId()).getColumnName());
				ofd.setColumnValue(masterData.get(onlineColumnService.getById(o.getMasterColumnId()).getColumnName()));
				ofd.setTableName(o.getSlaveTable().getTableName());
				filterList.add(ofd);
				List<Map<String, Object>> slaveDataList =onlineOperationService.getSlaveDataList(o, filterList, null);
				obj.put(String.valueOf(o.getRelationId()),slaveDataList);
			}
		});
        JSONObject re = new JSONObject();
		re.put("slaveData",obj);
		re.put("masterData",masterData);
		return R.data(re);
	}
	private IPage<Map<String, Object>> buildMasterData(
		OnlineTable masterTable, List<OnlineDatasourceRelation> relationList, List<OnlineFilterDto> filterList, String orderBy, Query query,String processDefinitionKey) {
		List<OnlineDatasourceRelation> oneToOneRelationList = relationList.stream()
			.filter(r -> r.getRelationType().equals(RelationType.ONE_TO_ONE)).collect(Collectors.toList());
		IPage<Map<String, Object>> result =
			onlineOperationService.getMasterDataPageList(masterTable, oneToOneRelationList, relationList, filterList, orderBy, query);
		if (result == null) {
			return null;
		}
		List<Map<String, Object>> list = result.getRecords();
		if (!list.isEmpty()) {
			FlowWorkOrder flowWorkOrder;


			for (Map<String, Object> map : list) {
				//根据id查询未提前停止工单信息
				flowWorkOrder = flowWorkOrderService.selectNotStoped(String.valueOf(map.get("id")), processDefinitionKey);
				if(flowWorkOrder != null ){
					map.put("process_definition_id", flowWorkOrder.getProcessDefinitionId());
					map.put("process_instance_id", flowWorkOrder.getProcessInstanceId());
					map.put("process_definition_key",flowWorkOrder.getProcessDefinitionKey());
					map.put("process_definition_name",flowWorkOrder.getProcessDefinitionName());

				}
			}
			List<String> instanceList = list.stream().map(map -> String.valueOf(map.get("process_instance_id"))).collect(Collectors.toList());
			List<Task> taskList = flowApiService.getTaskListByProcessInstanceIds(instanceList);
			Map<String, Task> taskMap = null;
			if (!taskList.isEmpty()) {
				//收集处理人
				List<String> collectAssignee = taskList.stream().filter(a -> StrUtil.isNotBlank(a.getAssignee())).map(TaskInfo::getAssignee).collect(Collectors.toList());
				if (collectAssignee.size() > 0) {
					userNameByAccounts = flowApiService.getUserNameByAccount(collectAssignee);
				}
				taskMap = taskList.stream().collect(Collectors.toMap(Task::getProcessInstanceId, Function.identity(), (task1, task2) -> {
					//判断处理人是否包含当前用户
					boolean b = false;
					TaskAssigneeDto taskAssigneeDtoTask1 = null;
					if (OnlineUtil.getJSONType(task1.getAssignee())) {
						 taskAssigneeDtoTask1 = JSONObject.parseObject(task1.getAssignee(), TaskAssigneeDto.class);
						b = Func.arrayContain(Func.toStrArray(taskAssigneeDtoTask1.getUserName()), SecureUtil.getUserAccount());
					}
					if (task1.getAssignee() != null && (task1.getAssignee().equals(SecureUtil.getUserAccount()) || b)) {
						TaskAssigneeDto taskAssigneeDto = new TaskAssigneeDto();
						if (task2.getAssignee() != null) {
							if (task1.getAssignee().equals(task2.getAssignee())) {
								taskAssigneeDto.setUserName(task1.getAssignee());
							}else if(OnlineUtil.getJSONType(task1.getAssignee())){
								if (taskAssigneeDtoTask1 != null && StrUtil.isNotBlank(taskAssigneeDtoTask1.getUserName())) {
									if(Func.arrayContain(Func.toStrArray(taskAssigneeDtoTask1.getUserName()),task2.getAssignee())){
										taskAssigneeDto.setUserName(taskAssigneeDtoTask1.getUserName());
									}else {
										taskAssigneeDto.setUserName(taskAssigneeDtoTask1.getUserName() + "," + task2.getAssignee());
									}
								}
							} else {
								taskAssigneeDto.setUserName(task1.getAssignee() + "," + task2.getAssignee());
							}
						} else {
							List<String> roleNames = flowApiService.getRoleNamByTaskId(task2.getId());
							if (OnlineUtil.getJSONType(task1.getAssignee()) && taskAssigneeDtoTask1 != null) {
								taskAssigneeDto.setUserName(taskAssigneeDtoTask1.getUserName());
								if(StrUtil.isNotBlank(taskAssigneeDtoTask1.getRoleName())){
									if(roleNames!=null && roleNames.size()>0){
										for (String roleName : roleNames) {
											if(Func.arrayContain(Func.toStrArray(taskAssigneeDtoTask1.getRoleName()),roleName)){
												taskAssigneeDto.setRoleName(taskAssigneeDtoTask1.getRoleName());
											}else {
												taskAssigneeDto.setRoleName(taskAssigneeDtoTask1.getRoleName() + "," + roleNames);
											}
										}
									}else {
										taskAssigneeDto.setRoleName(taskAssigneeDtoTask1.getRoleName());
									}
								}else {
									taskAssigneeDto.setRoleName(Func.join(roleNames));
								}
							}else{
							taskAssigneeDto.setUserName(task1.getAssignee());
							taskAssigneeDto.setRoleName(Func.join(roleNames));
							}
						}
						task1.setAssignee(JSON.toJSONString(taskAssigneeDto));
						return task1;
						} else {
							TaskAssigneeDto taskAssigneeDto = new TaskAssigneeDto();
							if(task1.getAssignee() != null ){
								if(OnlineUtil.getJSONType(task1.getAssignee())){
									if (taskAssigneeDtoTask1 != null && StrUtil.isNotBlank(taskAssigneeDtoTask1.getUserName())) {
										if (task2.getAssignee() != null) {
											if(!Func.arrayContain(Func.toStrArray(taskAssigneeDtoTask1.getUserName()), task2.getAssignee())){
												taskAssigneeDto.setUserName(taskAssigneeDtoTask1.getUserName() + "," + task2.getAssignee());
											}else {
												taskAssigneeDto.setUserName(taskAssigneeDtoTask1.getUserName());
											}
										} else {
											List<String> roleNames2 = flowApiService.getRoleNamByTaskId(task2.getId());
											if(StrUtil.isNotBlank(taskAssigneeDtoTask1.getRoleName())){
												if(roleNames2 !=null && roleNames2.size()>0){
													for (String roleName2 : roleNames2) {
														if(Func.arrayContain(Func.toStrArray(taskAssigneeDtoTask1.getRoleName()),roleName2)){
															taskAssigneeDto.setRoleName(taskAssigneeDtoTask1.getRoleName());
														}else {
															taskAssigneeDto.setRoleName(taskAssigneeDtoTask1.getRoleName() + "," + roleName2);
														}
													}
												}else {
													taskAssigneeDto.setRoleName(taskAssigneeDtoTask1.getRoleName());
												}
											}else {
												taskAssigneeDto.setRoleName(Func.join(roleNames2));
											}
										}
									}
								} else if (task2.getAssignee() != null) {
									if(task1.getAssignee().equals(task2.getAssignee())){
										taskAssigneeDto.setUserName(task1.getAssignee());
									}else {
										taskAssigneeDto.setUserName(task1.getAssignee() + "," + task2.getAssignee());
									}
								} else {
									taskAssigneeDto.setUserName(task1.getAssignee());
									List<String> roleName2 = flowApiService.getRoleNamByTaskId(task2.getId());
									taskAssigneeDto.setRoleName(Func.join(roleName2));
								}
							}else {
								List<String> roleName = flowApiService.getRoleNamByTaskId(task1.getId());
								taskAssigneeDto.setRoleName(Func.join(roleName));
								if (task2.getAssignee() != null) {
									taskAssigneeDto.setUserName(task2.getAssignee());
								} else {
									List<String> roleName2 = flowApiService.getRoleNamByTaskId(task2.getId());
									roleName2.addAll(roleName);
									Set<String> hashSet = new HashSet<>(roleName2);
									taskAssigneeDto.setRoleName(Func.join(hashSet));
								}
							}
							task2.setAssignee(JSON.toJSONString(taskAssigneeDto));
							return task2;
						}
					}));

			}
			if(taskMap != null && taskMap.size()>0) {
				List<ProcessInstance> pList = flowApiService.getProcessInstanceList(instanceList.stream().collect(Collectors.toSet()));
				Map<String, ProcessInstance> mapIns = pList.stream().collect(Collectors.toMap(ProcessInstance::getProcessInstanceId,Function.identity(), (task1, task2) -> task2));
				for (Map<String, Object> map : list) {
					Object status = map.get("status");
					if (status != null && status.toString().equals("保存草稿_save")) {
						TaskAssigneeDto taskAssigneeDto = new TaskAssigneeDto();
						Object createUserId = map.get("create_user_id");
						if (createUserId != null) {
						    String userId = createUserId.toString();

							String account = flowApiService.getUserById(Long.parseLong(userId));
							taskAssigneeDto.setAccount(account);
						}
						map.put("next_assignee", JSON.toJSONString(taskAssigneeDto));
					}
					Task t = (Task) taskMap.get(String.valueOf(map.get("process_instance_id")));
					if(t != null) {
						map.put("task_id", taskMap == null ? null : t.getId());
						map.put("task_name", taskMap == null ? null : t.getName());
						String assignee = t.getAssignee();
						if (assignee == null) {
							TaskAssigneeDto taskAssigneeDto = new TaskAssigneeDto();
							List<String> roleName = flowApiService.getRoleNamByTaskId(t.getId());
							taskAssigneeDto.setRoleName(Func.join(roleName));
							map.put("next_assignee", JSON.toJSONString(taskAssigneeDto));
						} else if (!OnlineUtil.getJSONType(assignee)) {
							TaskAssigneeDto taskAssigneeDto = new TaskAssigneeDto();
//							List<String> userNameCollect = userNameByAccounts.stream().filter(a -> a.getAccount().equals(assignee)).map(UserAssigneeDto::getRealName).collect(Collectors.toList());
//							if (userNameCollect.size() > 0) {
//								taskAssigneeDto.setUserName(userNameCollect.get(0));
//								map.put("next_assignee", JSON.toJSONString(taskAssigneeDto));
//							}
							for (UserAssigneeDto userNameByAccount : userNameByAccounts) {
								if(assignee.equals(userNameByAccount.getAccount())){
									taskAssigneeDto.setUserName(assignee);
									break;
								}
							}
							map.put("next_assignee", JSON.toJSONString(taskAssigneeDto));
						}else {
							TaskAssigneeDto taskAssigneeDto = JSONObject.parseObject(assignee, TaskAssigneeDto.class);
							if(taskAssigneeDto!=null && StrUtil.isNotBlank(taskAssigneeDto.getUserName())){
								String[] userAccounts = Func.toStrArray(taskAssigneeDto.getUserName());
								//转名
								if(userAccounts.length > 0){
									List<String> userNameList = new ArrayList<>();
									for (String userAccount : userAccounts) {
										for (UserAssigneeDto userNameByAccount : userNameByAccounts) {
											if(userAccount.equals(userNameByAccount.getAccount())){
												userNameList.add(userNameByAccount.getAccount());
												break;
											}
										}
									}
									if(userNameList.size()>0){
										taskAssigneeDto.setUserName(String.join(",", userNameList));
									}
								}
							}
							map.put("next_assignee", JSON.toJSONString(taskAssigneeDto));
						}
						ProcessInstance processInstance = mapIns.get(t.getProcessInstanceId());
						if(processInstance != null) {
							Object initiator = flowApiService.getProcessInstanceVariable(
								processInstance.getId(), FlowConstant.PROC_INSTANCE_INITIATOR_VAR);
							if (initiator != null) {
								map.put("process_instance_initiator", initiator.toString());
							}
						}
					}
				}
			}

			result.setRecords(list);
		}

		return result;
	}

	private R<Void> verifyFilterDtoList(List<OnlineFilterDto> filterDtoList) {
		if (CollUtil.isEmpty(filterDtoList)) {
			return R.data(null);
		}
		String errorMessage;
		for (OnlineFilterDto filter : filterDtoList) {
			if (!this.checkTableAndColumnName(filter.getTableName())) {
				errorMessage = "数据验证失败，过滤表名 ["
					+ filter.getColumnName() + " ] 包含 (数字、字母和下划线) 之外的非法字符！";
				return R.fail(errorMessage);
			}
			if (!this.checkTableAndColumnName(filter.getColumnName())) {
				errorMessage = "数据验证失败，过滤字段名 ["
					+ filter.getColumnName() + " ] 包含 (数字、字母和下划线) 之外的非法字符！";
				return R.fail(errorMessage);
			}
		}
		return R.data(null);
	}

	private boolean checkTableAndColumnName(String name) {
		if (StrUtil.isBlank(name)) {
			return true;
		}
		for (int i = 0; i < name.length(); i++) {
			char c = name.charAt(i);
			if (!CharUtil.isLetterOrNumber(c) && !CharUtil.equals('_', c, false)) {
				return false;
			}
		}
		return true;
	}
	/**
	 * 为数据源主表字段上传文件。
	 *
	 * @param processDefinitionKey 流程引擎流程定义标识。
	 * @param processInstanceId    流程实例Id。
	 * @param taskId               流程任务Id。
	 * @param datasourceId         数据源Id。
	 * @param relationId           数据源关联Id。
	 * @param fieldName            数据表字段名。
	 * @param asImage              是否为图片文件。
	 * @param uploadFile           上传文件对象。
	 */
//    @PostMapping("/upload")
//    public void upload(
//            @RequestParam String processDefinitionKey,
//            @RequestParam(required = false) String processInstanceId,
//            @RequestParam(required = false) String taskId,
//            @RequestParam Long datasourceId,
//            @RequestParam(required = false) Long relationId,
//            @RequestParam String fieldName,
//            @RequestParam Boolean asImage,
//            @RequestParam("uploadFile") MultipartFile uploadFile) throws Exception {
//        R<String> verifyResult =
//                this.verifyUploadOrDownload(processDefinitionKey, processInstanceId, taskId, datasourceId);
//        if (!verifyResult.isSuccess()) {
//            R.fail(HttpServletResponse.SC_FORBIDDEN, verifyResult.getMsg());
//            return;
//        }
//        R<OnlineTable> verifyTableResult =
//                this.verifyAndGetOnlineTable(datasourceId, relationId, null, null);
//        if (!verifyTableResult.isSuccess()) {
//			R.fail(HttpServletResponse.SC_FORBIDDEN, verifyTableResult.getMsg());
//            return;
//        }
//        onlineOperationHelper.doUpload(verifyTableResult.getData(), fieldName, asImage, uploadFile);
//		attachService.upload(uploadFile);
//    }

	/**
	 * 下载文件接口。
	 * 越权访问限制说明：
	 * taskId为空，当前用户必须为当前流程的发起人，否则必须为当前任务的指派人或候选人。
	 * relationId为空，下载数据为主表字段，否则为关联的从表字段。
	 * 该接口无需数据权限过滤，因此用DisableDataFilter注解标注。如果当前系统没有支持数据权限过滤，该注解不会有任何影响。
	 *
	 * @param processDefinitionKey 流程引擎流程定义标识。
	 * @param processInstanceId    流程实例Id。
	 * @param taskId               流程任务Id。
	 * @param datasourceId         数据源Id。
	 * @param relationId           数据源关联Id。
	 * @param dataId               附件所在记录的主键Id。
	 * @param fieldName            数据表字段名。
	 * @param asImage              是否为图片文件。
	 * @param response             Http 应答对象。
	 */
//    @DisableDataFilter
//    @GetMapping("/download")
//    public void download(
//            @RequestParam String processDefinitionKey,
//            @RequestParam(required = false) String processInstanceId,
//            @RequestParam(required = false) String taskId,
//            @RequestParam Long datasourceId,
//            @RequestParam(required = false) Long relationId,
//            @RequestParam(required = false) String dataId,
//            @RequestParam String fieldName,
//            @RequestParam String filename,
//            @RequestParam Boolean asImage,
//            HttpServletResponse response) throws Exception {
//        R<String> verifyResult =
//                this.verifyUploadOrDownload(processDefinitionKey, processInstanceId, taskId, datasourceId);
//        if (!verifyResult.isSuccess()) {
//            R.fail(HttpServletResponse.SC_FORBIDDEN, verifyResult.getMsg());
//            return;
//        }
//        R<OnlineTable> verifyTableResult =
//                this.verifyAndGetOnlineTable(datasourceId, relationId, verifyResult.getData(), dataId);
//        if (!verifyTableResult.isSuccess()) {
//            R.fail(HttpServletResponse.SC_FORBIDDEN, verifyTableResult.getMsg());
//            return;
//        }
//        onlineOperationHelper.doDownload(verifyTableResult.getData(), dataId, fieldName, filename, asImage, response);
//		attachService.down(response, Long.valueOf(dataId));
//    }

	/**
	 * 获取所有流程对象，同时获取关联的在线表单对象列表。
	 *
	 * @return 查询结果。
	 */
	@GetMapping("/listFlowEntryForm")
	@ApiOperation(notes = "获取所有流程对象，同时获取关联的在线表单对象列表", value = "获取所有流程对象，同时获取关联的在线表单对象列表")
	public R<List<FlowEntryVo>> listFlowEntryForm() {
		List<FlowEntry> flowEntryList = flowEntryService.list();
		List<FlowEntryVo> flowEntryVoList = FlowEntityWrapper.build().listVO(flowEntryList);
		if (CollUtil.isNotEmpty(flowEntryVoList)) {
			Set<Long> pageIdSet = flowEntryVoList.stream().map(FlowEntryVo::getPageId).collect(Collectors.toSet());
			List<OnlineForm> formList = onlineFormService.getOnlineFormListByPageIds(pageIdSet);
			Map<Long, List<OnlineForm>> formMap =
				formList.stream().collect(Collectors.groupingBy(OnlineForm::getPageId));
			for (FlowEntryVo flowEntryVo : flowEntryVoList) {
				List<OnlineForm> flowEntryFormList = formMap.get(flowEntryVo.getPageId());
				flowEntryVo.setFormList(MyModelUtil.beanToMapList(flowEntryFormList));
			}
		}
		return R.data(flowEntryVoList);
	}

	private R<OnlineDatasource> verifyAndGetOnlineDatasource(Long formId) {
		List<OnlineFormDatasource> formDatasourceList = onlineFormService.getFormDatasourceListByFormId(formId);
		if (CollUtil.isEmpty(formDatasourceList)) {
			String errorMessage = "数据验证失败，流程任务绑定的在线表单Id [" + formId + "] 不存在，请修改流程图！";
			return R.fail(errorMessage);
		}
		return onlineOperationHelper.verifyAndGetDatasource(formDatasourceList.get(0).getDatasourceId());
	}

	private JSONObject buildUserTaskData(
		String businessKey, OnlineTable masterTable, List<OnlineDatasourceRelation> relationList) {
		JSONObject jsonData = new JSONObject();
		List<OnlineDatasourceRelation> oneToOneRelationList = relationList.stream()
			.filter(r -> r.getRelationType().equals(RelationType.ONE_TO_ONE)).collect(Collectors.toList());
		Map<String, Object> result =
			onlineOperationService.getMasterData(masterTable, oneToOneRelationList, relationList, businessKey);
		if (MapUtil.isEmpty(result)) {
			return jsonData;
		}
		jsonData.put("masterAndOneToOne", result);
		List<OnlineDatasourceRelation> oneToManyRelationList = relationList.stream()
			.filter(r -> r.getRelationType().equals(RelationType.ONE_TO_MANY)).collect(Collectors.toList());
		if (CollUtil.isEmpty(oneToManyRelationList)) {
			return jsonData;
		}
		JSONObject oneToManyJsonData = new JSONObject();

		for (OnlineDatasourceRelation relation : oneToManyRelationList) {
			OnlineFilterDto filterDto = new OnlineFilterDto();
			filterDto.setTableName(relation.getSlaveTable().getTableName());
			OnlineColumn slaveColumn = relation.getSlaveTable().getColumnMap().get(relation.getSlaveColumnId());
			filterDto.setColumnName(slaveColumn.getColumnName());
			filterDto.setFilterType(FieldFilterType.EQUAL_FILTER);
			Object columnValue = result.get(masterTable.getColumnMap().get(relation.getMasterColumnId()).getColumnName());
			filterDto.setColumnValue(columnValue);
			List<Map<String, Object>> slaveResultList =
				onlineOperationService.getSlaveDataList(relation, CollUtil.newLinkedList(filterDto), null);
			if (CollUtil.isNotEmpty(slaveResultList)) {
				oneToManyJsonData.put(relation.getVariableName(), slaveResultList);
			}
		}
		jsonData.put("oneToMany", oneToManyJsonData);
		return jsonData;
	}

	private R<Void> submitNewTask(
		String processInstanceId,
		String taskId,
		FlowTaskComment flowTaskComment,
		JSONObject taskVariableData,
		OnlineTable masterTable,
		JSONObject masterData,
		JSONObject slaveData,
		Long datasourceId) {
		R<List<ColumnData>> columnDataListResult =
			onlineOperationHelper.buildTableData(masterTable, masterData, false, null);
		if (!columnDataListResult.isSuccess()) {
			return R.fail(columnDataListResult.getMsg());
		}
		// 保存在线表单提交的数据，同时启动流程和自动完成第一个用户任务。
		if (slaveData == null) {
			flowOfflineOperationService.saveNewAndTakeTask(
				processInstanceId,
				taskId,
				flowTaskComment,
				taskVariableData,
				masterTable,
				columnDataListResult.getData());
		} else {
			// 如果本次请求中包含从表数据，则一同插入。
			R<Map<OnlineDatasourceRelation, List<List<ColumnData>>>> slaveDataListResult =
				onlineOperationHelper.buildSlaveDataList(datasourceId, slaveData,false);
			if (!slaveDataListResult.isSuccess()) {
				return R.fail(slaveDataListResult.getMsg());
			}
			flowOfflineOperationService.saveNewAndTakeTask(
				processInstanceId,
				taskId,
				flowTaskComment,
				taskVariableData,
				masterTable,
				columnDataListResult.getData(),
				slaveDataListResult.getData());
		}
		return R.data(null);
	}

	private R<OnlineTable> verifyAndGetOnlineTable(
		Long datasourceId, Long relationId, String businessKey, String dataId) {
		R<OnlineDatasource> datasourceResult =
			onlineOperationHelper.verifyAndGetDatasource(datasourceId);
		if (!datasourceResult.isSuccess()) {
			return R.fail(datasourceResult.getMsg());
		}
		OnlineTable masterTable = datasourceResult.getData().getMasterTable();
		OnlineTable table = masterTable;
		R<OnlineDatasourceRelation> relationResult = null;
		if (relationId != null) {
			relationResult = onlineOperationHelper.verifyAndGetRelation(datasourceId, relationId);
			if (!relationResult.isSuccess()) {
				return R.fail(relationResult.getMsg());
			}
			table = relationResult.getData().getSlaveTable();
		}
		if (StrUtil.hasBlank(businessKey, dataId)) {
			return R.data(table);
		}
		String errorMessage;
		// 如果relationId为null，这里就是主表数据。
		if (relationId == null) {
			if (!StrUtil.equals(businessKey, dataId)) {
				errorMessage = "数据验证失败，参数主键Id与流程主表主键Id不匹配！";
				return R.fail(errorMessage);
			}
			return R.data(table);
		}
		OnlineDatasourceRelation relation = relationResult.getData();
		OnlineTable slaveTable = relation.getSlaveTable();
		Map<String, Object> dataMap =
			onlineOperationService.getMasterData(slaveTable, null, null, dataId);
		if (dataMap == null) {
			errorMessage = "数据验证失败，从表主键Id不存在！";
			return R.fail(errorMessage);
		}
		OnlineColumn slaveColumn = relation.getSlaveColumn();
		Object relationSlaveDataId = dataMap.get(slaveColumn.getColumnName());
		if (relationSlaveDataId == null) {
			errorMessage = "数据验证失败，当前关联的从表字段值为NULL！";
			return R.fail(errorMessage);
		}
		OnlineColumn masterColumn = masterTable.getColumnMap().get(relation.getMasterColumnId());
		if (masterColumn.getPrimaryKey()) {
			if (!StrUtil.equals(relationSlaveDataId.toString(), businessKey)) {
				errorMessage = "数据验证失败，当前从表主键Id关联的主表Id当前流程的BusinessKey不一致！";
				return R.fail(errorMessage);
			}
		}
		Map<String, Object> masterDataMap =
			onlineOperationService.getMasterData(masterTable, null, null, businessKey);
		if (masterDataMap == null) {
			errorMessage = "数据验证失败，主表主键Id不存在！";
			return R.fail(errorMessage);
		}
		Object relationMasterDataId = masterDataMap.get(masterColumn.getColumnName());
		if (relationMasterDataId == null) {
			errorMessage = "数据验证失败，当前关联的主表字段值为NULL！";
			return R.fail(errorMessage);
		}
		if (!StrUtil.equals(relationMasterDataId.toString(), relationSlaveDataId.toString())) {
			errorMessage = "数据验证失败，当前关联的主表字段值和从表字段值不一致！";
			return R.fail(errorMessage);
		}
		return R.data(table);
	}

	private R<String> verifyUploadOrDownload(
		String processDefinitionKey, String processInstanceId, String taskId, Long datasourceId) {
//        if (!StrUtil.isAllBlank(processInstanceId, taskId)) {
//            R<Void> verifyResult =
//                    flowOperationHelper.verifyUploadOrDownloadPermission(processInstanceId, taskId);
//            if (!verifyResult.isSuccess()) {
//                return R.fail(verifyResult.getMsg());
//            }
//        }
//        String errorMessage;
//        FlowEntry flowEntry = flowEntryService.getFlowEntryByProcessDefinitionKey(processDefinitionKey);
//        if (flowEntry == null) {
//            errorMessage = "数据验证失败，指定流程Id不存在！";
//            return R.fail(errorMessage);
//        }
//        String businessKey = null;
//        if (processInstanceId != null) {
//            HistoricProcessInstance instance = flowApiService.getHistoricProcessInstance(processInstanceId);
//            if (!StrUtil.equals(flowEntry.getProcessDefinitionKey(), instance.getProcessDefinitionKey())) {
//                errorMessage = "数据验证失败，指定流程实例并不属于当前流程！";
//                return R.fail(errorMessage);
//            }
//            businessKey = instance.getBusinessKey();
//        }
//        List<OnlinePageDatasource> datasourceList =
//                onlinePageService.getOnlinePageDatasourceListByPageId(flowEntry.getPageId());
//        Optional<Long> r = datasourceList.stream()
//                .map(OnlinePageDatasource::getDatasourceId).filter(c -> c.equals(datasourceId)).findFirst();
//        if (!r.isPresent()) {
//            errorMessage = "数据验证失败，当前数据源Id并不属于当前流程！";
//            return R.fail(errorMessage);
//        }
//        return R.data(businessKey);

		return null;
	}

	private R<Void> makeWorkOrderTaskInfo(List<FlowWorkOrderVo> flowWorkOrderVoList) {
		if (CollUtil.isEmpty(flowWorkOrderVoList)) {
			return R.data(null);
		}
		Set<String> definitionIdSet =
			flowWorkOrderVoList.stream().map(FlowWorkOrderVo::getProcessDefinitionId).collect(Collectors.toSet());
		List<FlowEntryPublish> flowEntryPublishList = flowEntryService.getFlowEntryPublishList(definitionIdSet);
		Map<String, FlowEntryPublish> flowEntryPublishMap =
			flowEntryPublishList.stream().collect(Collectors.toMap(FlowEntryPublish::getProcessDefinitionId, c -> c));
		for (FlowWorkOrderVo flowWorkOrderVo : flowWorkOrderVoList) {
			FlowEntryPublish flowEntryPublish = flowEntryPublishMap.get(flowWorkOrderVo.getProcessDefinitionId());
			flowWorkOrderVo.setInitTaskInfo(flowEntryPublish.getInitTaskInfo());
		}
		Set<String> businessKeySet =
			flowWorkOrderVoList.stream().map(FlowWorkOrderVo::getBusinessKey).collect(Collectors.toSet());
		Long tableId = flowWorkOrderVoList.get(0).getOnlineTableId();
		OnlineTable masterTable = onlineTableService.getOnlineTableFromCache(tableId);
		Set<?> convertedBusinessKeySet =
			onlineOperationHelper.convertToTypeValue(masterTable.getPrimaryKeyColumn(), businessKeySet);
		List<OnlineFilterDto> filterList = new LinkedList<>();
		OnlineFilterDto filterDto = new OnlineFilterDto();
		filterDto.setTableName(masterTable.getTableName());
		filterDto.setColumnName(masterTable.getPrimaryKeyColumn().getColumnName());
		filterDto.setFilterType(FieldFilterType.IN_LIST_FILTER);
		filterDto.setColumnValue(convertedBusinessKeySet);
		TaskInfoVo taskInfoVo = JSON.parseObject(flowWorkOrderVoList.get(0).getInitTaskInfo(), TaskInfoVo.class);
		// 验证在线表单及其关联数据源的合法性。
		String formName = taskInfoVo.getRouterName();
		QueryWrapper<OnlineForm> onlineFormQueryWrapper = new QueryWrapper<>();
		onlineFormQueryWrapper.eq("form_name", formName);
		OnlineForm onlineForm = onlineFormService.getOne(onlineFormQueryWrapper);
		R<OnlineDatasource> datasourceResult = this.verifyAndGetOnlineDatasource(onlineForm.getFormId());
		if (!datasourceResult.isSuccess()) {
			return R.fail(datasourceResult.getMsg());
		}
		OnlineDatasource datasource = datasourceResult.getData();
		R<List<OnlineDatasourceRelation>> relationListResult =
			onlineOperationHelper.verifyAndGetRelationList(datasource.getDatasourceId(), RelationType.ONE_TO_ONE);
		if (!relationListResult.isSuccess()) {
			return R.fail(relationListResult.getMsg());
		}
		List<Map<String, Object>> dataList = onlineOperationService.getMasterDataList(
			masterTable, relationListResult.getData(), null, filterList, null);
		Map<Object, Map<String, Object>> dataMap = dataList.stream()
			.collect(Collectors.toMap(c -> c.get(masterTable.getPrimaryKeyColumn().getColumnName()), c -> c));
		for (FlowWorkOrderVo flowWorkOrderVo : flowWorkOrderVoList) {
			Object dataId = onlineOperationHelper.convertToTypeValue(
				masterTable.getPrimaryKeyColumn(), flowWorkOrderVo.getBusinessKey());
			Map<String, Object> data = dataMap.get(dataId);
			if (data != null) {
				flowWorkOrderVo.setMasterData(data);
			}
		}
		List<String> unfinishedProcessInstanceIds = flowWorkOrderVoList.stream()
			.filter(c -> !c.getFlowStatus().equals(FlowTaskStatus.FINISHED))
			.map(FlowWorkOrderVo::getProcessInstanceId)
			.collect(Collectors.toList());
		if (CollUtil.isEmpty(unfinishedProcessInstanceIds)) {
			return R.data(null);
		}
		List<Task> taskList = flowApiService.getTaskListByProcessInstanceIds(unfinishedProcessInstanceIds);
		Map<String, List<Task>> taskMap =
			taskList.stream().collect(Collectors.groupingBy(Task::getProcessInstanceId));
		for (FlowWorkOrderVo flowWorkOrderVo : flowWorkOrderVoList) {
			List<Task> instanceTaskList = taskMap.get(flowWorkOrderVo.getProcessInstanceId());
			if (instanceTaskList == null) {
				continue;
			}
			JSONArray taskArray = new JSONArray();
			for (Task task : instanceTaskList) {
				JSONObject jsonObject = new JSONObject();
				jsonObject.put("taskId", task.getId());
				jsonObject.put("taskName", task.getName());
				jsonObject.put("taskKey", task.getTaskDefinitionKey());
				jsonObject.put("assignee", task.getAssignee());
				taskArray.add(jsonObject);
			}
			flowWorkOrderVo.setRuntimeTaskInfoList(taskArray);
		}
		return R.data(null);
	}

	private static String getMapToString(Map<String, Object> map) {
		Set<String> keySet = map.keySet();
		//将set集合转换为数组
		String[] keyArray = keySet.toArray(new String[keySet.size()]);
		//给数组排序(升序)
		Arrays.sort(keyArray);
		//因为String拼接效率会很低的，所以转用StringBuilder
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < keyArray.length; i++) {
			// 参数值为空，则不参与签名 这个方法trim()是去空格
			if ((String.valueOf(map.get(keyArray[i]))).trim().length() > 0) {
				sb.append(keyArray[i]).append(":").append(String.valueOf(map.get(keyArray[i])).trim());
			}
			if (i != keyArray.length - 1) {
				sb.append(",");
			}
		}
		return sb.toString();
	}

	private JSONObject masterDataBasic(JSONObject masterData, SysUser sysUser, int type,String formCode,String statusName) {
		if (masterData != null) {
		/*	if (type <= 1) {
				masterData.put("create_user_id", sysUser.getUserId());
				masterData.put("create_time", DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss"));
			}*/
			if(!masterData.containsKey("id") || StringUtils.isBlank(masterData.getString("id"))){
				masterData.put("create_user_id", sysUser.getUserId());
				masterData.put("create_time", DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss"));
				masterData.put("project_status",statusName);
			}
			if(type != StatusEnum.UPDATE.getValue()) {
				masterData.put("status", StatusEnum.getEnum(type).getDesc());
				masterData.put("form_code",formCode);
			}
			masterData.put("update_time", DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss"));
			masterData.put("update_user_id", sysUser.getUserId());

			masterData.put("is_deleted",0);
		}
		return masterData;
	}

	public JSONObject salveDataBasic(JSONObject slaveData, SysUser sysUser, int type) {
		String slaveStr = JSON.toJSONString(slaveData,SerializerFeature.WriteMapNullValue);
		log.info("slaveStr{}", slaveStr);
		Map<String, JSONArray> maps = JSON.parseObject(slaveStr, Map.class);
		Iterator<Map.Entry<String, JSONArray>> it = maps.entrySet().iterator();
		JSONObject re = new JSONObject();
		while (it.hasNext()) {
			Map.Entry<String, JSONArray> map = it.next();
			JSONArray jarr = map.getValue();

			for (int i = 0; i < jarr.size(); i++) {

				if(!jarr.getJSONObject(i).containsKey("id") || StringUtils.isBlank(jarr.getJSONObject(i).getString("id"))){
					jarr.getJSONObject(i).put("create_user_id", sysUser.getUserId());
					jarr.getJSONObject(i).put("create_time", DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss"));
				}
				jarr.getJSONObject(i).put("update_user_id", sysUser.getUserId());
				jarr.getJSONObject(i).put("update_time", new Date());
				jarr.getJSONObject(i).put("is_deleted",0);
				//jarr.getJSONObject(i).put("status", StatusEnum.getEnum(type).getValue());
			}
			re.put(String.valueOf(map.getKey()), jarr);
		}
		log.info("slaveData{}", JSON.toJSONString(re,SerializerFeature.WriteMapNullValue));
		return re;
	}

}
